You might be wondering why you have to do anything special to
run native code at all. After all, .NET has good support for
interoperating with native code—from P/Invoke to COM Interop. However,
those mechanisms don’t work out of the box on Windows Azure because of the sandbox in which your code
runs.
1. Hypervisor and Standard User Privileges
All user code in Windows Azure runs on the Windows Azure hypervisor. Also, any code that runs in
Windows Azure runs under the context of a “standard user” (as opposed to
a “user with administrative privileges”).
This distinction is important, because this is something that
cannot be opted out of, regardless of whether you’re running native or
managed code. Actions that require administrative-level privileges on
the machine (such as installing drivers, or changing system binaries or
protected parts of the registry) will fail.
Warning: You should always ensure that your code doesn’t require
administrative privileges. One common “gotcha” is that the Dev Fabric
runs under the context of your user account on your local machine. If
you’re the local administrator on your machine (as most of us are),
your code will seem to execute fine, but will fail in the cloud. To
avoid these issues, consider using a low-privileged account to test
your code locally.
2. Windows Azure Partial Trust
By default, all managed code on Windows Azure runs on a restricted
trust level called Windows Azure partial trust. Because the user account is not an administrator on the virtual
machine, this adds even further restrictions than those imposed by
Windows. This trust level is enforced by .NET’s Code Access
Security (CAS) support.
Users familiar with CAS might recognize this as being very similar
to the “medium trust” level in .NET. Access is granted only to certain
resources and operations. Table 1 shows some of the
key resources and operations, and their restrictions on access. In
general, your code is allowed only to connect to external IP addresses
over TCP, and is limited to accessing files and folders only in its
“local store,” as opposed to any location on the system. Any libraries
that your code uses must either work in partial trust or be specially
marked with an “allow partially trusted callers” attribute.
Table 1. Windows Azure partial trust restrictions
Permission | State | Details |
---|
AspNetHosting | Level | Medium |
DnsPermission | Unrestricted | Permitted |
EnvironmentPermission | Unrestricted/Read/Write | TEMP; TMP |
FileIOPermission | Read | App directory, any named
local store |
| Write | Any named local
store |
RegistryPermission | Unrestricted | Denied |
SocketPermission | Connect | External sites only over
TCP |
| Accept | Denied |
WebPermission | Connect | External sites
only |
Why run code in such a restrictive environment by default? The
idea is to be secure by default. If your web application gets
compromised in some way, the attacker is limited in the amount of damage
he can do. For example, a malicious attacker couldn’t modify any of your
ASP.NET pages on disk by default, or change any of the system
binaries.
However, the downside of such a restrictive environment is that it
is, well, restrictive. Several useful libraries (such as those used for
accessing the registry, or accessing a well-known file location) don’t
work in such an environment for trivial reasons. Even some of
Microsoft’s own frameworks don’t work in this environment because they
don’t have the “partially trusted caller” attribute set.
. Full Trust and Native Code
For the first several months after the launch of Windows
Azure, the partial trust environment was the only one available to
users. As a part of the March 2009 MIX release, Windows Azure added a
key option: the ability to run code under full trust, instead of the partial
trust environment described previously. “Full trust” here refers to the
least-restrictive permission level allowed by .NET CAS. Running under
full trust means the code has access to anything the Windows user
account it is running under has access to.
Specifying that a role should have full trust privileges is easy.
Add an enableNativeCodeExecution (yes, the name is a bit of a mismatch)
attribute in the service definition file with its value set to true, as shown in Example 1.
Example 1. Full-trust privileges for a role
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="HelloWorldService" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
<WebRole name="WebRole" enableNativeCodeExecution="true"> <InputEndpoints> <InputEndpoint name="HttpIn" protocol="http" port="80" /> </InputEndpoints> </WebRole> </ServiceDefinition>
|
The name enableNativeCodeExecution hints at the
possibilities that get opened up with this option set. Running code
under full trust means managed code can not only P/Invoke to native code, but also launch
other native processes. This last bit of functionality is important, and it is
often used to support additional languages/environments on Windows
Azure.